#pragma once
#include <stdexcept>
#include <algorithm>
#include <iostream>

namespace zcb
{
	typedef size_t size_type;
#define SMALL_STRING_CAPACITY 15
	[[noreturn]] inline void _Xlen_string() {
   		throw std::length_error("string too long");
	}

	template<class T>
	_NODISCARD size_type getCharPtrLength(const T* const ptr)
	{
		int count = 0;
		while (ptr[count] != T())
		{
			++count;
		}
		return count;
	}

	_NODISCARD size_type caculateCapacity(const size_type size);

	template <class CharType>
	class zcb_basic_string
	{

	private:
		CharType* _data;
		size_type _len;
		size_type _size;
		size_type _capacity;


	private:
		using value_type = CharType;
	public:
		zcb_basic_string(const value_type* const ptr)
		{
			_len = getCharPtrLength(ptr);
			_size = _len;
			_capacity = caculateCapacity(_size);
			_data = new value_type[_capacity];

			int count = 0;
			while (count < _len)
			{
				_data[count] = ptr[count];
				++count;
			}
			_data[_len] = '\0';
		}

		zcb_basic_string(zcb_basic_string<CharType>& source, const value_type* left, const size_type left_size,
			const value_type* const right, const size_type right_size)
		{
			const size_type merg_size = left_size + right_size;
			_len = merg_size;
			_size = _len;
			_capacity = source.capacity();
			if (_capacity < merg_size)
			{
				_capacity = caculateCapacity(_size);
				_data = new CharType[_capacity];
				for (int i = 0; i < merg_size; ++i)
				{
					if (i < left_size)
						_data[i] = source._data[i];
					else
						_data[i] = right[i- left_size];
				}
				_data[merg_size] = '\0';
				delete[] source._data;

				//this = new (&source) zcb_basic_string(new_data); // 原地构造
			}
			else
			{
				 
				_data = source._data;
				for (int i = 0; i < right_size; ++i)
				{
					_data[i + left_size] = right[i];
				}

				_data[merg_size] = '\0';
				source._data = nullptr;
			}
			

		}


		zcb_basic_string(const value_type* const left, const size_type left_size, 
			zcb_basic_string<CharType>& source, const value_type* right, const size_type right_size)
		{
			const size_type merg_size = left_size + right_size;
			_len = merg_size;
			_size = merg_size;
			_capacity = source.capacity();
			if (_capacity < merg_size)
			{
				_capacity = caculateCapacity(_size);
				_data = new CharType[_capacity];
				for (int i = 0; i < merg_size; ++i)
				{
					if (i < left_size)
						_data[i] = left[i];
					else
						_data[i] = right[i - left_size];
				}
				_data[merg_size] = '\0';
				delete[] source._data;
			}
			else
			{
				size_type i = right_size - 1;
				_data = source.data();
				while (i > -1)
				{
					_data[i + left_size] = right[i];
					--i;
				}
				
				for (i = 0; i < left_size; ++i)
				{
					_data[i] = left[i];
				}

				_data[merg_size] = '\0';
				source._data = nullptr;
			}
		}

		~zcb_basic_string()
		{
			   
			delete[] _data;
		}


	public:
		inline size_type length() const { return _len; }

		inline size_type size() const { return _size; }

		inline size_type capacity() const{ return _capacity; }

		inline value_type* data() const { return _data; }

		zcb_basic_string<CharType>& operator+=(const value_type* ptr)
		{
			return zcb_basic_string<CharType>();
		}
		
		template<class CharType>
		_NODISCARD _CONSTEXPR20 zcb_basic_string<CharType>& operator=(zcb_basic_string<CharType>&& right)
		{
			std::cout << "enter\n";
			if (this != &right)
			{
				delete[] _data;

				this->_data = right._data;
				this->_capacity = right._capacity;
				this->_len = right._len;
				this->_size = right._size;

				right._data = nullptr;

				return *this;
			}
			return *this;
		}

	public:
		template <class CharType>
		friend std::ostream& operator<<(std::ostream& os, const zcb_basic_string<CharType>& cT);

		value_type& operator[](const size_type _Off)
		{
			return _data[_Off];
		}

	};

	template <class CharType>
	std::ostream& operator<<(std::ostream& os, const zcb_basic_string<CharType>& cT)
	{
		os << cT._data;
		return os;
	}

	template<class CharType>
	_NODISCARD _CONSTEXPR20 zcb_basic_string<CharType> operator+(zcb_basic_string<CharType>& left,
		const CharType* const right)
	{
		// _NODISCARD 用于防止忽略函数返回值，帮助开发者发现潜在的逻辑错误,告诉你必须使用变量接受返回值或者使用返回值，否则会警告
		//_CONSTEXPR20, 当你定义一个函数，它可以在编译时计算其结果，从而可能提高性能并减少运行时开销。
		const auto left_size = left.size();
		const auto right_size = getCharPtrLength(right);
		if (UINT64_MAX - left_size < right_size)
		{
			_Xlen_string();
		}
		return { left, left.data(), left_size, right, right_size};
	}

	template<class CharType>
	_NODISCARD _CONSTEXPR20 zcb_basic_string<CharType> operator+(const CharType* const left, 
		zcb_basic_string<CharType>& right)
	{
		const auto left_size = getCharPtrLength(left);
		if (UINT64_MAX - left_size < right.size())
		{
			_Xlen_string();
		}
		return { left, left_size, right, right.data(), right.size() };
	}

	using string = zcb_basic_string<char>;
}

